home *** CD-ROM | disk | FTP | other *** search
/ Hot Super Models / Hot Super Models.iso / unix / x11 / xv200.tar / xv-2.00 / xvevent.c < prev    next >
C/C++ Source or Header  |  1992-01-02  |  30KB  |  1,132 lines

  1. /*
  2.  * xvevent.c - EventLoop and support routines for XV
  3.  *
  4.  *  Author:    John Bradley, University of Pennsylvania
  5.  *                (bradley@cis.upenn.edu)
  6.  *
  7.  *  Contains:
  8.  *            int  EventLoop()
  9.  *            void DrawWindow(x,y,w,h)
  10.  *            void WResize(w,h)
  11.  *            void WRotate()
  12.  *            void WCrop(w,h)
  13.  *            void WUnCrop()
  14.  *            void GetWindowPos(&xwa)
  15.  *            void SetWindowPos(&xwa)
  16.  *     static void TrackCrop(mx,my)
  17.  *     static void CropKey(dx,dy,grow)
  18.  *     static int  Rect(x,y,x1,y1)
  19.  *            void InvCropRect()
  20.  *     static void TrackPicValues(mx,my)
  21.  *     static int  CheckForConfig()
  22.  *            void SetEpicMode()
  23.  *            int  xvErrorHandler(disp, err)
  24.  */
  25.  
  26.  
  27. /*
  28.  * Copyright 1989, 1990, 1991, 1992 by John Bradley and
  29.  *                       The University of Pennsylvania
  30.  *
  31.  * Permission to use, copy, and distribute for non-commercial purposes,
  32.  * is hereby granted without fee, providing that the above copyright
  33.  * notice appear in all copies and that both the copyright notice and this
  34.  * permission notice appear in supporting documentation. 
  35.  *
  36.  * The software may be modified for your own purposes, but modified versions
  37.  * may not be distributed.
  38.  *
  39.  * This software is provided "as is" without any expressed or implied warranty.
  40.  *
  41.  * The author may be contacted via:
  42.  *    US Mail:   John Bradley
  43.  *               GRASP Lab, Room 301C
  44.  *               3401 Walnut St.  
  45.  *               Philadelphia, PA  19104
  46.  *
  47.  *    Phone:     (215) 898-8813
  48.  *    EMail:     bradley@cis.upenn.edu       
  49.  */
  50.  
  51.  
  52. #define NEEDSTIME    /* for -wait handling in eventloop */
  53.  
  54. #include "xv.h"
  55.  
  56. static int    rotatesLeft = 0;
  57.  
  58. /* local function pre-definitions */
  59. #ifdef __STDC__
  60. static void WMaximize(void);
  61. static void TrackCrop(int, int);
  62. static void CropKey(int, int, int);
  63. static int  Rect(int, int, int, int);
  64. static void TrackPicValues(int, int);
  65. static int  CheckForConfig(void);
  66. #else
  67. static void WMaximize(), TrackCrop(), CropKey(), TrackPicValues();
  68. static int  Rect(), CheckForConfig();
  69. #endif
  70.  
  71.  
  72.  
  73.  
  74. /****************/
  75. int EventLoop()
  76. /****************/
  77. {
  78.   XEvent event;
  79.   int    retval,done,waiting;
  80.   time_t orgtime, curtime;
  81.  
  82.  
  83.   /* note: there's no special event handling if we're using the root window.
  84.      if we're using the root window, we will recieve NO events for mainW */
  85.  
  86.  
  87.   done = retval = waiting = 0;
  88.   while (!done) {
  89.  
  90.     if (waitsec > -1 && !waiting && XPending(theDisp)==0) {
  91.       /* we wanna wait, we haven't started waiting yet, and all pending
  92.      events (ie, drawing the image the first time) have been dealt with */
  93.  
  94.       time(&orgtime);
  95.       waiting = 1;
  96.     }
  97.  
  98.  
  99.     if (waitsec == -1 || XPending(theDisp)>0) {
  100.       XNextEvent(theDisp, &event);
  101.       retval = HandleEvent(&event,&done);
  102.     }
  103.  
  104.     else {                      /* no events.  check wait status */
  105.       if (waitsec>-1 && waiting) {
  106.     time(&curtime);
  107.     if (curtime - orgtime < waitsec) sleep(1);
  108.     else {
  109.       if (waitloop) return NEXTLOOP;
  110.       else return NEXTQUIT;
  111.     }
  112.       }
  113.     }
  114.   }  /* while (!done) */
  115.  
  116.   return(retval);
  117. }
  118.  
  119.  
  120.  
  121. /****************/
  122. int HandleEvent(event, donep)
  123. XEvent *event;
  124. int *donep;
  125. {
  126.   int done=0, retval=0;
  127.  
  128.   switch (event->type) {
  129.  
  130.   case ClientMessage: {
  131.     Atom proto, delwin;
  132.     XClientMessageEvent *client_event = (XClientMessageEvent *) event;
  133.  
  134.     if (PUCheckEvent (event)) break;   /* event has been processed */
  135.  
  136.     proto = XInternAtom(theDisp, "WM_PROTOCOLS", FALSE);
  137.     delwin = XInternAtom(theDisp, "WM_DELETE_WINDOW", FALSE);
  138.  
  139.     if (client_event->message_type == proto &&
  140.     client_event->data.l[0]    == delwin) {
  141.       /* it's a WM_DELETE_WINDOW event */
  142.  
  143.       if      (client_event->window == infoW) InfoBox(0);
  144.       else if (client_event->window == gamW)  GamBox(0);
  145.       else if (client_event->window == ctrlW) CtrlBox(0);
  146.       else if (client_event->window == dirW)  DirBox(0);
  147.       else if (client_event->window == psW)   PSDialog(0);
  148. #ifdef HAVE_JPEG
  149.       else if (client_event->window == jpegW) JPEGDialog(0);
  150. #endif
  151.       else if (client_event->window == mainW) exit(0);
  152.     }
  153.   }
  154.     break;
  155.  
  156.  
  157.   case Expose: {
  158.     XExposeEvent *exp_event = (XExposeEvent *) event;
  159.     int x,y,w,h;
  160.     Window win;
  161.  
  162.     win = exp_event->window;
  163.     x = exp_event->x;      y = exp_event->y;
  164.     w = exp_event->width;  h = exp_event->height;
  165.     
  166.     if (PUCheckEvent  (event)) break;   /* event has been processed */
  167.     if (PSCheckEvent  (event)) break;   /* event has been processed */
  168. #ifdef HAVE_JPEG
  169.     if (JPEGCheckEvent(event)) break;   /* event has been processed */
  170. #endif
  171.     if (GamCheckEvent (event)) break;   /* event has been processed */
  172.  
  173.     /* if the window doesn't do intelligent redraw, drop all-1 exposes */
  174.     if (exp_event->count>0 && exp_event->window != mainW 
  175.                        && exp_event->window != ctrlW
  176.                        && exp_event->window != dirW
  177.                        && exp_event->window != infoW) break;
  178.  
  179.     if (win == mainW) {
  180.       if (DEBUG) fprintf(stderr,"EXPOSE:  ");
  181.       if (!CheckForConfig()) {
  182.     if (DEBUG) fprintf(stderr,"No configs. Expose %d,%d %dx%d\n",x,y,w,h);
  183.     if (DEBUG) XClearArea(theDisp, mainW, x,y,w,h, False);
  184.  
  185.     DrawWindow(x,y,w,h);
  186.         
  187.     if (but[BCROP].active) {
  188.       XRectangle xr;
  189.       xr.x = x;  xr.y = y;  xr.width = w;  xr.height = h;
  190.       
  191.       XSetClipRectangles(theDisp,theGC,0,0,&xr,1,Unsorted);
  192.       InvCropRect();
  193.       XSetClipMask(theDisp,theGC,None);
  194.     }
  195.       }
  196.       else
  197.     if (DEBUG) 
  198.       fprintf(stderr,"Ignoring expose event.  Config pending\n");
  199.     }
  200.  
  201.     else if (win == infoW)          RedrawInfo(x,y,w,h);
  202.     else if (win == ctrlW)          RedrawCtrl(x,y,w,h);
  203.     else if (win == nList.win)      LSRedraw(&nList);
  204.     else if (win == nList.scrl.win) SCRedraw(&nList.scrl);
  205.     else if (win == dirW)           RedrawDirW(x,y,w,h);
  206.     else if (win == dList.win)      LSRedraw(&dList);
  207.     else if (win == dList.scrl.win) SCRedraw(&dList.scrl);
  208.     else if (win == dnamW)          RedrawDNamW();
  209.   }      
  210.     break;
  211.     
  212.  
  213.   case ButtonPress: {
  214.     XButtonEvent *but_event = (XButtonEvent *) event;
  215.     int i,x,y;
  216.     Window win;
  217.  
  218.     win = but_event->window;
  219.     x = but_event->x;  y = but_event->y;
  220.  
  221.     if (PUCheckEvent  (event)) break;
  222.     if (PSCheckEvent  (event)) break;
  223. #ifdef HAVE_JPEG
  224.     if (JPEGCheckEvent(event)) break;
  225. #endif
  226.     if (GamCheckEvent (event)) break;
  227.  
  228.     switch (but_event->button) {
  229.  
  230.     case Button1:  
  231.       if      (win == mainW) TrackPicValues(x,y);
  232.  
  233.       else if (win == ctrlW) {
  234.     int   w,h;
  235.  
  236.     if (MBClick(&dispMB, x,y)) {
  237.       if (MBTrack(&dispMB)) HandleDispMode();
  238.       break;
  239.     }
  240.  
  241.     i=ClickCtrl(x,y);
  242.  
  243.     switch (i) {
  244.     case BNEXT:   retval= NEXTPIC;  done=1;  break;
  245.     case BPREV:   retval= PREVPIC;  done=1;  break;
  246.  
  247.     case BLOAD:   SetDirFName("");  DirBox(BLOAD);   break;
  248.  
  249.     case BSAVE:   DirBox(BSAVE);
  250.                       break;
  251.  
  252.     case BQUIT:   retval= QUIT;     done=1;  break;
  253.         
  254.     case BCROP:   DoCrop();  break;
  255.     case BUNCROP: UnCrop();  break;
  256.     case BNORM:   WResize(cWIDE/normFact, cHIGH/normFact);  break;
  257.     case BMAX:    WMaximize();  break;
  258.     case BUP10:   w = (eWIDE*11)/10;  h = (eHIGH*11)/10;
  259.                   if (w==eWIDE) w++;
  260.                   if (h==eHIGH) h++;
  261.                   WResize(w,h);
  262.                   break;
  263.  
  264.     case BDN10:   WResize((eWIDE*9)/10, (eHIGH*9)/10);  break;
  265.     case BUP2:    WResize(eWIDE*2, eHIGH*2);  break;
  266.     case BDN2:    WResize(eWIDE/2, eHIGH/2);  break;
  267.     case B4BY3:   w = eWIDE;  h = (w * 3) / 4;
  268.                       if (h>maxHIGH) { h = eHIGH;  w = (h*4)/3; }
  269.                       WResize(w,h);
  270.                       break;
  271.  
  272.     case BASPECT: FixAspect(1,&w,&h);  WResize(w,h);  break;
  273.     case BMAXPECT: { int w1,h1;
  274.              w1 = eWIDE;  h1 = eHIGH;
  275.              eWIDE = dispWIDE;  eHIGH = dispHIGH;
  276.              FixAspect(0,&w,&h);
  277.              eWIDE = w1;  eHIGH = h1;  /* play it safe */
  278.              WResize(w,h);
  279.                }   break;
  280.  
  281.     case BROTL:   Rotate(1);  break;
  282.     case BROTR:   Rotate(0);  break;
  283.  
  284.     case BACROP:  AutoCrop();  break;
  285.  
  286.     case BFLIPH:  Flip(0);   break;
  287.     case BFLIPV:  Flip(1);   break;
  288.     case BSMOOTH: Smooth();  break; 
  289.     case BDITH:   ColorDither(NULL, eWIDE, eHIGH);  break;
  290.     case BRAW:    if (theImage!=NULL) XDestroyImage(theImage);
  291.               theImage = NULL;
  292.               Resize(eWIDE,eHIGH);
  293.               break;
  294.  
  295.     case BINFO:   InfoBox(!infoUp); break;
  296.     case BGAMMA:  GamBox(!gamUp);   break;
  297.  
  298.     case BDELETE: if (DeleteCmd()) { done = 1;  retval = DELETE; }
  299.                   break;
  300.  
  301.     default:      break;
  302.     }
  303.  
  304.     if (i==BFLIPH || i==BFLIPV || i==BSMOOTH || i==BDITH || i==BRAW) {
  305.       if (useroot) MakeRootPic();
  306.               else DrawWindow(0,0,eWIDE,eHIGH);
  307.       if (but[BCROP].active) InvCropRect();
  308.       SetCursors(-1);
  309.     }
  310.       }
  311.  
  312.       else if (win == nList.win) {
  313.     i=LSClick(&nList,but_event);
  314.     if (i>=0) { done = 1;  retval = i; }
  315.       }
  316.  
  317.       else if (win == nList.scrl.win) SCTrack(&nList.scrl, x, y);
  318.  
  319.       else if (win == dirW) {
  320.     i=ClickDirW(x,y);
  321.         
  322.     switch (i) {
  323.     case S_BOK:   if (dirUp == BLOAD) {
  324.                     retval = LOADPIC;
  325.                 done=1;
  326.               }
  327.                   else if (dirUp == BSAVE) {
  328.                 DoSave();
  329.               }
  330.                   break;
  331.  
  332.     case S_BCANC: DirBox(0);  break;
  333.     }
  334.       }
  335.  
  336.       else if (win == dList.win) {
  337.     i=LSClick(&dList,but_event);
  338.     SelectDir(i);
  339.       }
  340.  
  341.       else if (win == dList.scrl.win) SCTrack(&dList.scrl, x,y);
  342.       else if (win == infoW)          InfoBox(0);  /* close info */
  343.  
  344.       break;
  345.  
  346.  
  347.     case Button2:  if (win == mainW) TrackCrop(x,y);
  348.                    break;
  349.  
  350.     case Button3:  /* if using root, MUST NOT get rid of ctrlbox. */
  351.                if (!useroot) CtrlBox(!ctrlUp); 
  352.                    break;
  353.  
  354.     default:       break;
  355.     }
  356.   }
  357.     break;
  358.  
  359.     
  360.   case KeyPress: {
  361.     XKeyEvent *key_event = (XKeyEvent *) event;
  362.     char buf[128];  KeySym ks;  XComposeStatus status;  
  363.     int stlen, dealt, shift;
  364.     
  365.     stlen = XLookupString(key_event,buf,128,&ks,&status);
  366.     dealt = 0;
  367.  
  368.     if (PUCheckEvent  (event)) break;
  369.     if (PSCheckEvent  (event)) break;
  370. #ifdef HAVE_JPEG
  371.     if (JPEGCheckEvent(event)) break;
  372. #endif
  373.     if (GamCheckEvent (event)) break;
  374.  
  375.     /* check for crop rect keys */
  376.     if (key_event->window == mainW  /*  && !dirUp */) {
  377.       dealt = 1;  shift = key_event->state & ShiftMask;
  378.       if      (ks==XK_Left  || ks==XK_KP_4) CropKey(-1, 0, shift);
  379.       else if (ks==XK_Right || ks==XK_KP_6) CropKey( 1, 0, shift);
  380.       else if (ks==XK_Up    || ks==XK_KP_8) CropKey( 0,-1, shift);
  381.       else if (ks==XK_Down  || ks==XK_KP_2) CropKey( 0, 1, shift);
  382.       else dealt = 0;
  383.       if (dealt) break;
  384.     }
  385.  
  386.  
  387.     /* check for List keys */
  388.     if (key_event->window == ctrlW || key_event->window == dirW /*||dirUp*/) {
  389.       LIST *theList;
  390.  
  391.       if (key_event->window == dirW /*|| dirUp*/) theList = &dList;
  392.       else theList = &nList;
  393.  
  394.       dealt = 1;
  395.       if      (ks==XK_Prior) LSKey(theList,LS_PAGEUP);
  396.       else if (ks==XK_Next)  LSKey(theList,LS_PAGEDOWN);
  397.       else if (ks==XK_Up)    LSKey(theList,LS_LINEUP);
  398.       else if (ks==XK_Down)  LSKey(theList,LS_LINEDOWN);
  399.       else if (ks==XK_Home)  LSKey(theList,LS_HOME);
  400.       else if (ks==XK_End)   LSKey(theList,LS_END);
  401.       else dealt = 0;
  402.  
  403.       if (theList == &dList && dealt) {  /* changed dir selection */
  404.     SelectDir(-1);  /* nothing was double-clicked */
  405.       }
  406.       
  407.       if (dealt) break;
  408.     }
  409.  
  410.     /* check dir filename arrows */
  411.     if (key_event->window == dirW && ks==XK_Left)  { DirKey('\002'); break; }
  412.     if (key_event->window == dirW && ks==XK_Right) { DirKey('\006'); break; }
  413.  
  414.  
  415.     if (!stlen) break;
  416.  
  417.     /* if dirUp, send all keystrokes to it OR NOT */
  418.     if (key_event->window == dirW /* || dirUp */) {
  419.       if (DirKey(buf[0])) XBell(theDisp,0);
  420.     }
  421.  
  422.     else {
  423.       /* commands valid in any window */
  424.       
  425.       switch (buf[0]) {
  426.       case '\t':
  427.       case ' ':    FakeButtonPress(&but[BNEXT]);    break;
  428.  
  429.       case '\r':
  430.       case '\n':   done = 1;  retval = nList.selected; break; 
  431.  
  432.       case '\010':
  433.       case '\177': FakeButtonPress(&but[BPREV]);    break;
  434.  
  435.       case '\004': FakeButtonPress(&but[BDELETE]);  break;  /* ^D */
  436.       case '\014': FakeButtonPress(&but[BLOAD]);    break;  /* ^L */
  437.       case '\023': FakeButtonPress(&but[BSAVE]);    break;  /* ^S */
  438.  
  439.       case 'q':    FakeButtonPress(&but[BQUIT]);    break;
  440.     
  441.       case '?':    if (!useroot) CtrlBox(!ctrlUp);  break;
  442.  
  443.       case 's':    FakeButtonPress(&but[BSMOOTH]);  break;
  444.       case 'd':    FakeButtonPress(&but[BDITH]);    break;
  445.       case 'r':    FakeButtonPress(&but[BRAW]);     break;
  446.         
  447.       case 'a':    FakeButtonPress(&but[BASPECT]);  break;
  448.       case 'A':    FakeButtonPress(&but[BACROP]);   break;
  449.  
  450.       case 'T':    FakeButtonPress(&but[BROTL]);    break;
  451.       case 't':    FakeButtonPress(&but[BROTR]);    break;
  452.       case 'h':    FakeButtonPress(&but[BFLIPH]);   break;
  453.       case 'v':    FakeButtonPress(&but[BFLIPV]);   break;
  454.       case '4':    FakeButtonPress(&but[B4BY3]);    break;
  455.       case 'c':    FakeButtonPress(&but[BCROP]);    break;
  456.       case 'u':    FakeButtonPress(&but[BUNCROP]);  break;
  457.       case 'n':    FakeButtonPress(&but[BNORM]);    break;
  458.       case 'm':    FakeButtonPress(&but[BMAX]);     break;
  459.       case 'M':    FakeButtonPress(&but[BMAXPECT]); break;
  460.       case ',':    FakeButtonPress(&but[BDN10]);    break;
  461.       case '.':    FakeButtonPress(&but[BUP10]);    break;
  462.       case '<':    FakeButtonPress(&but[BDN2]);     break;
  463.       case '>':    FakeButtonPress(&but[BUP2]);     break;
  464.  
  465.       case 'i':    FakeButtonPress(&but[BINFO]);    break;
  466.       case 'e':    FakeButtonPress(&but[BGAMMA]);   break;
  467.  
  468.       case 'R':    FakeButtonPress(&gbut[G_BRESET]);   break;
  469.       case 'p':    FakeButtonPress(&gbut[G_BAPPLY]);    break;
  470.       case 'C':    FakeButtonPress(&gbut[G_BMAXCONT]);  break;
  471.  
  472.       default:     break;
  473.       }
  474.     }
  475.   }
  476.     break;
  477.     
  478.  
  479.  
  480.   case ConfigureNotify: {
  481.     XConfigureEvent *conf_event = (XConfigureEvent *) event;
  482.  
  483.     if (conf_event->window == mainW && !rotatesLeft) {
  484.       if (DEBUG) fprintf(stderr,"CONFIG: (%s) ", 
  485.              conf_event->send_event ? "program" : "user");
  486.  
  487.       if (CheckForConfig()) {
  488.     if (DEBUG) fprintf(stderr,"config pending.  ignored\n");
  489.       }
  490.       else {
  491.     XEvent xev;
  492.     if (DEBUG) fprintf(stderr,"No configs pend.");
  493.  
  494.     if (conf_event->width == eWIDE && conf_event->height == eHIGH) {
  495.       if (DEBUG) fprintf(stderr,"No redraw\n");
  496.     }
  497.     else {
  498.       if (DEBUG) fprintf(stderr,"Do full redraw\n");
  499.       Resize(conf_event->width, conf_event->height);
  500.  
  501.       /* eat any pending expose events and do a full redraw */
  502.       while (XCheckTypedWindowEvent(theDisp, mainW, Expose, &xev)) {
  503.         XExposeEvent *exp = (XExposeEvent *) &xev;
  504.         if (DEBUG) 
  505.           fprintf(stderr,"  ate expose (%s) (count=%d) %d,%d %dx%d\n",
  506.               exp->send_event ? "program" : "user", exp->count,
  507.               exp->x, exp->y, exp->width, exp->height);
  508.       }
  509.  
  510.       DrawWindow(0,0,conf_event->width, conf_event->height);
  511.       SetCursors(-1);
  512.     }
  513.       }
  514.     }
  515.  
  516.     if (rotatesLeft>0) rotatesLeft--;
  517.     if (!rotatesLeft) SetCursors(-1);
  518.   }
  519.     break;
  520.     
  521.  
  522.     
  523.   case CirculateNotify:
  524.   case MapNotify:
  525.   case DestroyNotify:
  526.   case GravityNotify:
  527.   case UnmapNotify:         break;
  528.  
  529.   case ReparentNotify: {
  530.     XReparentEvent *reparent_event = (XReparentEvent *) event;
  531.  
  532.     if (DEBUG) {
  533.       fprintf(stderr,"Reparent: mainW=%x ->win=%x ->ev=%x  ->parent=%x  ", 
  534.           mainW, reparent_event->window, reparent_event->event, 
  535.           reparent_event->parent);
  536.       fprintf(stderr,"%d,%d\n", reparent_event->x, reparent_event->y);
  537.     }
  538.  
  539.     if (reparent_event->window == mainW) {
  540.       ch_offx = reparent_event->x;  /* offset required for ChangeAttr call */
  541.       ch_offy = reparent_event->y;
  542.  
  543.       p_offx = p_offy = 0;          /* topleft correction for WMs titlebar */
  544.  
  545.       if (ch_offx == 0 && ch_offy == 0) {  
  546.     /* looks like the user is running MWM or OLWM */
  547.  
  548.     XWindowAttributes xwa;
  549.  
  550.     /* first query the attributes of mainW.  x,y should be the offset
  551.        from the parent's topleft corner to the windows topleft.
  552.        OLWM puts the info here */
  553.  
  554.     XSync(theDisp, False);
  555.     XGetWindowAttributes(theDisp, mainW, &xwa);
  556.     
  557.     if (DEBUG) 
  558.       fprintf(stderr,"XGetAttr: mainW %d,%d %dx%d\n", xwa.x, xwa.y,
  559.           xwa.width, xwa.height);
  560.  
  561.     if (xwa.x == 0 && xwa.y == 0) {
  562.       /* MWM, at least mine, puts 0's in those fields.  To get the
  563.          info, we'll have to query the parent window */
  564.  
  565.       XSync(theDisp, False);
  566.       XGetWindowAttributes(theDisp, reparent_event->parent, &xwa);
  567.     
  568.       if (DEBUG) 
  569.         fprintf(stderr,"XGetAttr: parent %d,%d %dx%d\n", xwa.x, xwa.y,
  570.             xwa.width, xwa.height);
  571.     }
  572.     else {
  573.       /* KLUDGE:  if we're running olwm, xwa.{x,y} won't be 0,0.
  574.          in olwm, the window drifts down and right each time
  575.          SetWindowPos() is called.  God knows why.  Anyway, I'm
  576.          inserting a kludge here to increase 'ch_offx' and 'ch_offy'
  577.          by bwidth so that this drifting won't happen.  No doubt this'll
  578.          screw up behavior on some *other* window manager, but it should
  579.          work with TWM, OLWM, and MWM (the big three) */
  580.       ch_offx += bwidth;
  581.       ch_offy += bwidth;
  582.     }
  583.  
  584.     p_offx = xwa.x;
  585.     p_offy = xwa.y;
  586.       }
  587.     }
  588.   }
  589.     break;
  590.     
  591.  
  592.   case EnterNotify:
  593.   case LeaveNotify: {
  594.     XCrossingEvent *cross_event = (XCrossingEvent *) event;
  595.     if (cross_event->window != mainW) break;
  596.  
  597.     if (cross_event->type == EnterNotify && LocalCmap && !ninstall) 
  598.       XInstallColormap(theDisp,LocalCmap);
  599.  
  600.     if (cross_event->type == LeaveNotify && LocalCmap && !ninstall) 
  601.       XUninstallColormap(theDisp,LocalCmap);
  602.   }
  603.     break;
  604.     
  605.     
  606.   default: break;        /* ignore unexpected events */
  607.   }  /* switch */
  608.  
  609.   *donep = done;
  610.   return(retval);
  611. }
  612.  
  613.  
  614.  
  615. /***********************************/
  616. void DrawWindow(x,y,w,h)
  617. int x,y,w,h;
  618. {
  619.   if (theImage)
  620.     XPutImage(theDisp,mainW,theGC,theImage,x,y,x,y,w,h);
  621.   else 
  622.     if (DEBUG) fprintf(stderr,"Tried to DrawWindow when theImage was NIL\n");
  623. }
  624.  
  625.  
  626. /***********************************/
  627. void WResize(w,h)
  628. int w,h;
  629. {
  630.   XWindowAttributes xwa;
  631.  
  632.   RANGE(w,1,maxWIDE);  RANGE(h,1,maxHIGH);
  633.  
  634.   if (useroot) {
  635.     Resize(w,h);
  636.     MakeRootPic();
  637.     SetCursors(-1);
  638.     return;
  639.   }
  640.  
  641.   /* determine if new size goes off edge of screen.  if so move window so it
  642.      doesn't go off screen */
  643.  
  644.   GetWindowPos(&xwa);
  645.   if (xwa.x + w > vrWIDE) xwa.x = vrWIDE - w;
  646.   if (xwa.y + h > vrHIGH) xwa.y = vrHIGH - h;
  647.  
  648.   if (DEBUG) fprintf(stderr,"%s: resizing window to %d,%d at %d,%d\n",
  649.              cmd,w,h,xwa.x,xwa.y);
  650.  
  651.   /* resize the window */
  652.   xwa.width = w;  xwa.height = h;
  653.  
  654.   SetWindowPos(&xwa);
  655. }
  656.  
  657.  
  658.  
  659.  
  660. /***********************************/
  661. static void WMaximize()
  662. {
  663.   XWindowAttributes xwa;
  664.  
  665.   if (useroot) WResize(dispWIDE, dispHIGH);
  666.   else {
  667.     xwa.x = xwa.y = 0;
  668.     xwa.width  = dispWIDE;  
  669.     xwa.height = dispHIGH;
  670.     SetWindowPos(&xwa);
  671.   }
  672. }
  673.  
  674.  
  675.  
  676.  
  677. /***********************************/
  678. void WRotate()
  679. {
  680.   /* rotate the window and redraw the contents  */
  681.  
  682.   if (but[BCROP].active) BTSetActive(&but[BCROP],0);
  683.   if (useroot) {
  684.     MakeRootPic();
  685.     SetCursors(-1);
  686.     return;
  687.   }
  688.  
  689.   if (eWIDE == eHIGH) {     /* no configure events will be gen'd */
  690.     Resize(eWIDE, eHIGH);   /* to regen Ximage */
  691.     DrawWindow(0, 0, eWIDE, eHIGH);
  692.     SetCursors(-1);
  693.   }
  694.   else {
  695.     rotatesLeft++;
  696.     WResize(eWIDE, eHIGH);
  697.   }
  698. }
  699.  
  700.  
  701.  
  702. /***********************************/
  703. void WCrop(w,h)
  704. int w,h;
  705. {
  706.   XWindowAttributes xwa;
  707.  
  708.   if (useroot) {
  709.     Resize(w,h);        /* generate new epic and theImage */
  710.     MakeRootPic();
  711.     SetCursors(-1);
  712.     return;
  713.   }
  714.  
  715.   /* we want to move window to old x,y + crx1,cry1 */
  716.   GetWindowPos(&xwa);
  717.   xwa.x += crx1;  xwa.y += cry1;
  718.   xwa.width = w;  xwa.height = h;
  719.   SetWindowPos(&xwa);
  720. }
  721.  
  722.  
  723. /***********************************/
  724. void WUnCrop()
  725. {
  726.   int w,h;
  727.   XWindowAttributes xwa;
  728.  
  729.  
  730.   /* to uncrop, I need to know the old values of cXOFF and cYOFF (cx,cy), and
  731.      the old values of cWIDE,cHIGH, eWIDE, eHIGH.  NOTE that the idea here
  732.      is to, if possible, uncrop by wrapping the rest of the picture around
  733.      the currently visible hunk.  */
  734.  
  735.   if (!useroot) GetWindowPos(&xwa);
  736.  
  737.   /* calculate w,h:  based on concept of trying to show uncropped picture
  738.      with same expansion ratios.  If this isn't possible (w or h bigger
  739.      than screen), just go to good ol' 1:1 expansion */
  740.  
  741.   w = (pWIDE * eWIDE) / cWIDE;  h = (pHIGH * eHIGH) / cHIGH;
  742.  
  743.   if (w>maxWIDE || h>maxHIGH) {
  744.     w=pWIDE / normFact;  h=pHIGH / normFact;
  745.     if (xwa.x + w > vrWIDE) xwa.x = vrWIDE - w;
  746.     if (xwa.y + h > vrHIGH) xwa.y = vrHIGH - h;
  747.     xwa.width = w;  xwa.height = h;
  748.     if (!useroot) SetWindowPos(&xwa);
  749.   }
  750.  
  751.   else {
  752.     xwa.x = xwa.x - (cXOFF*eWIDE)/cWIDE;   xwa.y = xwa.y - (cYOFF*eHIGH)/cHIGH;
  753.     if (xwa.x<0) xwa.x = 0;
  754.     if (xwa.y<0) xwa.y = 0;
  755.     xwa.width = w;  xwa.height = h;
  756.     if (!useroot) SetWindowPos(&xwa);
  757.   }
  758.  
  759.   if (useroot) {
  760.     cpic = pic;  cWIDE = pWIDE;  cHIGH = pHIGH;
  761.     Resize(xwa.width, xwa.height);        /* generate new epic and theImage */
  762.     MakeRootPic();
  763.     SetCursors(-1);
  764.     return;
  765.   }
  766.  
  767. }
  768.  
  769.  
  770.  
  771. /***********************************/
  772. void GetWindowPos(xwa)
  773. XWindowAttributes *xwa;
  774. {
  775.   Window child;
  776.   
  777.   /* returns the x,y,w,h coords of mainW.  x,y are relative to rootW 
  778.      the border is not included (x,y map to top-left pixel in window) */
  779.  
  780.   /* Get the window width/height */
  781.   XGetWindowAttributes(theDisp,mainW,xwa);
  782.  
  783.   /* Get the window origin */
  784.   XTranslateCoordinates(theDisp,mainW,rootW,0,0,&xwa->x,&xwa->y,&child);
  785. }
  786.  
  787.  
  788. /***********************************/
  789. void SetWindowPos(xwa)
  790. XWindowAttributes *xwa;
  791. {
  792.   /* sets window x,y,w,h values */
  793.   Window            root, parent, *children, child;
  794.   unsigned int      nchildren;
  795.   int               x, y, w, h, xact, yact;
  796.   XWindowChanges    xwc;
  797.  
  798.   /* Adjust from window origin, to border origin */
  799.   xwc.x = xwa->x - xwa->border_width - ch_offx;
  800.   xwc.y = xwa->y - xwa->border_width - ch_offy;
  801.  
  802.   if (!xwa->border_width) xwa->border_width = bwidth;
  803.   xwc.border_width = xwa->border_width;
  804.  
  805.   /* if we're less than max size in one axis, allow window manager doohickeys
  806.      on the screen */
  807.   
  808.   if (xwa->width  < dispWIDE && xwc.x < p_offx) xwc.x = p_offx;
  809.   if (xwa->height < dispHIGH && xwc.y < p_offy) xwc.y = p_offy;
  810.  
  811.   xwc.width  = xwa->width;
  812.   xwc.height = xwa->height;
  813.  
  814.   if (DEBUG) {
  815.     fprintf(stderr,"SWP: xwa=%d,%d %dx%d  xwc=%d,%d %dx%d  off=%d,%d bw=%d\n",
  816.         xwa->x, xwa->y, xwa->width, xwa->height,
  817.         xwc.x, xwc.y, xwc.width, xwc.height, p_offx, p_offy, 
  818.         xwa->border_width);
  819.   }
  820.  
  821. #ifndef DXWM
  822.   /* Move/Resize the window. */
  823.   XConfigureWindow(theDisp, mainW, 
  824.            CWX | CWY | CWWidth | CWHeight /*| CWBorderWidth*/, &xwc);
  825. #endif
  826. }
  827.  
  828.  
  829. /***********************************/
  830. static void TrackCrop(mx,my)
  831. int mx,my;
  832. {
  833.   Window       rW,cW;
  834.   int          rx,ry,ox,oy,x,y,active;
  835.   unsigned int mask;
  836.  
  837.   if (but[BCROP].active) {             /* turn off old cropping rectangle */
  838.     XSetFunction(theDisp,theGC,GXinvert);
  839.     Rect(crx1,cry1,crx2,cry2);
  840.     XSetFunction(theDisp,theGC,GXcopy);
  841.   }
  842.   active = 0;
  843.   SetCropString(active);
  844.  
  845.   crx1 = ox = mx;  cry1 = oy = my;         /* nail down one corner */
  846.  
  847.   while (1) {
  848.     if (XQueryPointer(theDisp,mainW,&rW,&cW,&rx,&ry,&x,&y,&mask)) {
  849.       if (!(mask & Button2Mask)) break;    /* button released */
  850.  
  851.       if (x!=ox || y!=oy) {                /* moved.  erase and redraw */
  852.     crx2 = x;  cry2 = y;
  853.     XSetFunction(theDisp,theGC,GXinvert);
  854.     Rect(crx1,cry1,ox,oy);
  855.     active = Rect(crx1,cry1,crx2,cry2);
  856.     XSetFunction(theDisp,theGC,GXcopy);
  857.     XFlush(theDisp);
  858.     ox=crx2;  oy=cry2;
  859.     if (infoUp) SetCropString(active);
  860.       }
  861.     }
  862.   }
  863.  
  864.   RANGE(crx1,0,eWIDE);  RANGE(cry1,0,eHIGH);
  865.   RANGE(crx2,0,eWIDE);  RANGE(cry2,0,eHIGH);
  866.   BTSetActive(&but[BCROP],active);
  867.   SetCropString(active);
  868. }
  869.  
  870.  
  871. /***********************************/
  872. static void CropKey(dx,dy,grow)
  873. int dx,dy,grow;
  874. {
  875.   int x1,x2,y1,y2,active;
  876.  
  877.   if (!but[BCROP].active) return;
  878.  
  879.   /* x1,y1 = top-left,  x2,y2 = bot-right */
  880.   if (crx1<crx2) { x1=crx1;  x2=crx2; }   else { x1=crx2;  x2=crx1; }
  881.   if (cry1<cry2) { y1=cry1;  y2=cry2; }   else { y1=cry2;  y2=cry1; }
  882.  
  883.   if (!grow) {    /* move the rectangle */
  884.     x1 += dx;  x2 += dx;  y1 += dy;  y2 += dy;
  885.     if (x1<0 || x2>eWIDE) { x1 -= dx;  x2 -= dx; }
  886.     if (y1<0 || y2>eHIGH) { y1 -= dy;  y2 -= dy; }
  887.   }
  888.   else {          /* grow the rectangle, pref. keeping top-left anchored */
  889.     x2 += dx;  y2 += dy;
  890.     if (x2>eWIDE) { 
  891.       x1 -= dx;  x2 -= dx;
  892.       if (x1<0) x1=0;
  893.     }
  894.  
  895.     if (y2>eHIGH) { 
  896.       y1 -= dy;  y2 -= dy;
  897.       if (y1<0) y1=0;
  898.     }
  899.   }
  900.     
  901.   XSetFunction(theDisp,theGC,GXinvert);
  902.   Rect(crx1,cry1,crx2,cry2);
  903.   crx1 = x1;  cry1 = y1;  crx2 = x2;  cry2 = y2;
  904.   active = Rect(crx1,cry1,crx2,cry2);
  905.   XSetFunction(theDisp,theGC,GXcopy);
  906.  
  907.   BTSetActive(&but[BCROP], active);
  908.   SetCropString(active);
  909. }
  910.  
  911.   
  912. /***********************************/
  913. static int Rect(x,y,x1,y1)
  914. int x,y,x1,y1;
  915. {
  916.   int w,h;
  917.  
  918.   /* returns 0 if it didn't draw anything (rect is too small), 1 if it did */
  919.   w = abs(x-x1);  h = abs(y-y1);
  920.   if (x>x1) x = x1;
  921.   if (y>y1) y = y1;
  922.  
  923.   /* keep rectangle inside window */  
  924.   if (x<0) { w+=x; x=0; }
  925.   if (y<0) { h+=y; y=0; }
  926.   if (x+w>eWIDE) w=eWIDE-x;  
  927.   if (y+h>eHIGH) h=eHIGH-y;
  928.  
  929.   if (w<4 || h<4) return 0;   /* too small */
  930.  
  931.   XSetPlaneMask(theDisp, theGC, AllPlanes);
  932.   XDrawRectangle(theDisp, mainW, theGC, x, y, w-1, h-1);
  933.   XSetPlaneMask(theDisp, theGC, 1L);
  934.   XDrawRectangle(theDisp, mainW, theGC, x+1, y+1, w-3, h-3);
  935.   XSetPlaneMask(theDisp, theGC, AllPlanes);
  936.   return 1;
  937. }
  938.  
  939.  
  940. /***********************************/
  941. void InvCropRect()
  942. {
  943.   XSetFunction(theDisp,theGC,GXinvert);
  944.   Rect(crx1,cry1,crx2,cry2);
  945.   XSetFunction(theDisp,theGC,GXcopy);
  946. }
  947.  
  948.  
  949. /***********************************/
  950. static void TrackPicValues(mx,my)
  951. int mx,my;
  952. {
  953.   Window       rW,cW;
  954.   int          rx,ry,ox,oy,x,y;
  955.   unsigned int mask;
  956.   int          ty, w, ecol;
  957.   char         foo[64];
  958.   unsigned long wh, bl;
  959.   char         *str  = "8888,8888 = 123,123,123  (123,123,123 HSV)";
  960.  
  961.   wh = infobg;  bl = infofg;
  962.  
  963.   /* do a colormap search for black and white if LocalCmap 
  964.      and use those colors instead of infobg and infofg */
  965.   if (LocalCmap) {
  966.     XColor ctab[256];
  967.     int  i;
  968.     long cval;
  969.  
  970.     for (i=0; i<nfcols; i++) ctab[i].pixel = freecols[i];
  971.     XQueryColors(theDisp,LocalCmap,ctab,nfcols);
  972.     
  973.     /* find 'blackest' pixel */
  974.     cval = 0x10000 * 3;
  975.     for (i=0; i<nfcols; i++)
  976.       if (ctab[i].red + ctab[i].green + ctab[i].blue < cval) {
  977.     cval = ctab[i].red + ctab[i].green + ctab[i].blue;
  978.     bl = ctab[i].pixel;
  979.       }
  980.  
  981.     /* find 'whitest' pixel */
  982.     cval = -1;
  983.     for (i=0; i<nfcols; i++)
  984.       if ((long)ctab[i].red + (long)ctab[i].green + (long)ctab[i].blue >cval) {
  985.     cval = ctab[i].red + ctab[i].green + ctab[i].blue;
  986.     wh = ctab[i].pixel;
  987.       }
  988.   }
  989.  
  990.   XSetFont(theDisp, theGC, monofont);
  991.   w = XTextWidth(monofinfo, str, strlen(str));
  992.  
  993.   if (my > eHIGH/2) ty = 0;
  994.                else ty = eHIGH-(monofinfo->ascent + mfinfo->descent)-4;
  995.  
  996.   ox = oy = -1;  /* kludge to force redraw first time through */
  997.  
  998.   XSetForeground(theDisp, theGC, bl);
  999.   XFillRectangle(theDisp, mainW, theGC, 0, ty, w + 8, 
  1000.          (monofinfo->ascent+monofinfo->descent) + 4);
  1001.   XSetForeground(theDisp, theGC, wh);
  1002.   XSetBackground(theDisp, theGC, bl);
  1003.   foo[0] = '\0';
  1004.  
  1005.   RANGE(x,0,eWIDE-1);   RANGE(y,0,eHIGH-1);
  1006.   rx = cXOFF + (x * cWIDE) / eWIDE;
  1007.   ry = cYOFF + (y * cHIGH) / eHIGH;
  1008.   ecol = pic[ry * pWIDE + rx];
  1009.  
  1010.   while (1) {
  1011.     int px, py, pix;
  1012.  
  1013.     if (XQueryPointer(theDisp,mainW,&rW,&cW,&rx,&ry,&x,&y,&mask)) {
  1014.       if (!(mask & Button1Mask)) break;    /* button released */
  1015.  
  1016.       RANGE(x,0,eWIDE-1);  
  1017.       RANGE(y,0,eHIGH-1);
  1018.  
  1019.       px = cXOFF + (x * cWIDE) / eWIDE;
  1020.       py = cYOFF + (y * cHIGH) / eHIGH;
  1021.  
  1022.       if (px!=ox || py!=oy) {                /* moved.  erase and redraw */
  1023.     double h1, s1, v1;
  1024.  
  1025.     ecol = pix = pic[py * pWIDE + px];
  1026.  
  1027.     rgb2hsv(rcmap[pix],gcmap[pix],bcmap[pix],&h1,&s1,&v1);
  1028.     if (h1<0.0) h1 = 0.0;   /* map 'NOHUE' to 0.0 */
  1029.  
  1030.     sprintf(foo,"%4d,%4d = %3d,%3d,%3d  (%3d %3d %3d HSV)",
  1031.         px, py, rcmap[pix],gcmap[pix],bcmap[pix], 
  1032.         (int) h1, (int) (s1 * 100), (int) (v1 * 100));
  1033.     
  1034.     XDrawImageString(theDisp,mainW,theGC, 4, ty + 2 + monofinfo->ascent, 
  1035.             foo, strlen(foo));
  1036.     ox = px;  oy = py;
  1037.       }
  1038.     }
  1039.   }
  1040.  
  1041.   if (foo[0]) XStoreBytes(theDisp, foo, strlen(foo));
  1042.  
  1043.   XSetFont(theDisp, theGC, mfont);
  1044.   DrawWindow(0,ty,eWIDE,(monofinfo->ascent+monofinfo->descent)+4);
  1045.   if (ecol != editColor) ChangeEC(ecol);
  1046. }
  1047.  
  1048.  
  1049. /***********************************/
  1050. static Bool IsConfig(dpy, ev, arg)
  1051. Display *dpy;
  1052. XEvent  *ev;
  1053. char    *arg;
  1054. {
  1055.   XConfigureEvent *cev;
  1056.  
  1057.   if (ev->type == ConfigureNotify) {
  1058.     cev = (XConfigureEvent *) ev;
  1059.     if (cev->window == mainW && (cev->width != eWIDE || cev->height != eHIGH))
  1060.       *arg = 1;
  1061.   }
  1062.   return False;
  1063. }
  1064.  
  1065. /***********************************/
  1066. static int CheckForConfig()
  1067. {
  1068.   XEvent ev;
  1069.   char   foo;
  1070.  
  1071.   /* returns true if there's a config event in which mainW changes size
  1072.      in the event queue */
  1073.   
  1074.   XSync(theDisp, False);
  1075.   foo = 0;
  1076.   XCheckIfEvent(theDisp, &ev, IsConfig, &foo);
  1077.   return foo;
  1078. }
  1079.  
  1080.  
  1081. /************************************************************************/
  1082. void SetEpicMode()
  1083. {
  1084.   if (epicmode == EM_RAW) {
  1085.     BTSetActive(&but[BRAW],   0);
  1086.     BTSetActive(&but[BDITH],  (ncols>0) );  /* only enable dith if ncols>0 */
  1087.     BTSetActive(&but[BSMOOTH],1);
  1088.   }
  1089.  
  1090.   else if (epicmode == EM_DITH) {
  1091.     BTSetActive(&but[BRAW],   1);
  1092.     BTSetActive(&but[BDITH],  0);
  1093.     BTSetActive(&but[BSMOOTH],1);
  1094.   }
  1095.  
  1096.   else if (epicmode == EM_SMOOTH) {
  1097.     BTSetActive(&but[BRAW],   1);
  1098.     BTSetActive(&but[BDITH],  0);
  1099.     BTSetActive(&but[BSMOOTH],1);  /* color editing may require a re-smooth */
  1100.   }
  1101. }
  1102.  
  1103.  
  1104. /************************************************************************/
  1105. int xvErrorHandler(disp, err)
  1106. Display *disp;
  1107. XErrorEvent *err;
  1108. {
  1109.   char buf[128];
  1110.  
  1111.   xerrcode = err->error_code;
  1112.  
  1113.   /* BadAlloc errors (on a XCreatePixmap() call)
  1114.      and BadAccess errors on XFreeColors are 'ignoreable' errors */
  1115.  
  1116.   if (xerrcode == BadAlloc || 
  1117.       (xerrcode == BadAccess && err->request_code==88)) return 0;
  1118.  
  1119.   else {
  1120.     /* all other errors are 'fatal' */
  1121.     XGetErrorText(disp, xerrcode, buf, 128);
  1122.     fprintf(stderr,"X Error: %s\n",buf);
  1123.     fprintf(stderr,"  Major Opcode:  %d\n",err->request_code);
  1124.     
  1125.     exit(-1);
  1126.   }
  1127.  
  1128.   return 0;
  1129. }
  1130.  
  1131.  
  1132.